﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.ComponentModel;
using System.Diagnostics;
using System.Threading;
using System.Net;

namespace FLKRP.WP7.Server.Server
{
    class ClientManager : INotifyPropertyChanged
    {
        private bool _running;

        public event PropertyChangedEventHandler PropertyChanged;

        //Listener is used to accept new connections.
        Listener _listener;

        public ClientManager()
        {
            IPAddresses =  Dns.GetHostEntry(Dns.GetHostName()).AddressList
                    .Where(addr => addr.AddressFamily == System.Net.Sockets.AddressFamily.InterNetwork)
                    .OrderBy(addr=>addr.ToString())
                    .Select(addr => addr.ToString()).ToList();

            _listener = new Listener(IPAddress.Any, Common.ListenerPort);
            _listener.ClientConnected += (sndr, args) =>
            {
                AddClient(new Client(args.Socket));
            };            
        }

        //All the connected clients.
        List<Client> _clients = new List<Client>();
        //When sending data if it fails, the client will be added to this list to later be removed.
        List<Client> _clientsToRemove = new List<Client>();

        private int _connectedClientCount;
        public int ConnectedClientCount
        {
            get { return _connectedClientCount; }
            set
            {
                if (_connectedClientCount != value)
                {
                    _connectedClientCount = value;
                    if (PropertyChanged != null)
                    {
                        PropertyChanged(this, new PropertyChangedEventArgs("ConnectedClientCount"));
                        PropertyChanged(this, new PropertyChangedEventArgs("ConnectionStatus"));
                    }
                }
            }
        }

        public List<String> IPAddresses { get; set; }

        public string ConnectionStatus
        {
            set {}
            get { return string.Format("Number of connected clients: {0}", _connectedClientCount); }
        }

        public void AddClient(Client client)
        {
            ConnectedClientCount++;

            client.SocketClosed += (sender, args) =>
            {
                _clientsToRemove.Add(sender as Client);
                Debug.WriteLine("Socket Closed!");
                ConnectedClientCount--;
            };

            _clients.Add(client);
        }

        public void Start()
        {
            _listener.Start();

            var clientManagerThread = new Thread(() =>
            {
                _running = true;
                while (_running)
                {
                    _clients.ForEach(client => client.ReadBytes());
                    Thread.Sleep(50);
                }

            });

            clientManagerThread.Start();
        }

        public void SendData(string data)
        {
            data += "X"; //Add an X to the end of the array, this will be replaced with a 0x00 to 
            //notify the client that the data has been completed.

            var encodedBytes = new UTF8Encoding().GetBytes(data);
            encodedBytes[encodedBytes.Length - 1] = 0x00;

            //Potentially at some point use UDP to send the data out to multiple clients.
            _clients.ForEach(client => client.SendData(encodedBytes));

            //If we can't send data to the client this class will be notified the client failed.
            //it will be added to the _clientsToRemove list to be removed from future notifications.
            _clientsToRemove.ForEach(client => _clients.Remove(client));

            //After removing, 
            _clientsToRemove.Clear();
        }

        public void Stop()
        {
            _clients.ForEach(client => client.Close());
            _clients.Clear();
            _listener.Stop();

            _running = false;
        }

    }
}
